package com.jiezuo.auth.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Joiner;
import com.jiezuo.auth.entity.Depart;
import com.jiezuo.auth.entity.Permission;
import com.jiezuo.auth.mapper.PermissionMapper;
import com.jiezuo.auth.service.DepartService;
import com.jiezuo.auth.service.PermissionService;
import com.jiezuo.common.constant.SysConstant;
import com.jiezuo.common.exception.BusinessRuntimeException;
import com.jiezuo.common.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author 王帅
 * @Date 2020/7/29 10:47
 * @Version 1.0
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

    //读取文件路径
    @Value("${file.file-read-path}")
    private String fileReadPath;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private DepartService departService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public List<Map<String, Object>> findRoleAndPermissionByUser(String user_id, String user_name) {
        List<Map<String, Object>> roleAndPermissionByUserId = permissionMapper.findRoleAndPermissionByUserId(user_id);
        redisTemplate.opsForValue().set(SysConstant.REDIS_DATA_AUTHORITY + user_name, JSON.toJSON(roleAndPermissionByUserId).toString());
        return roleAndPermissionByUserId;
    }

    @Override
    public List<String> findByUserId(String user_id) {
        return permissionMapper.findByUserId(user_id);
    }

    @Override
    public List<Permission> menuTree(Permission permission) {
        QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
        if (StringUtil.isNotEmpty(permission.getBelongs())) queryWrapper.eq("belongs", permission.getBelongs());
        queryWrapper.orderByAsc("sort");
        queryWrapper.eq("is_delete", "0");
        List<Permission> permissionList = this.list(queryWrapper);
        permissionList.forEach(it -> {
            if (StringUtil.isNotEmpty(it.getBackground_image()))
                it.setBg_image(fileReadPath + it.getBackground_image());
        });
        List<Permission> permissions = iterateMenus(permissionList, "0", permission.getResource_name());
        return permissions;
    }

    @Override
    public List<Permission> getChildren(String pid, String resource_name, String belongs) {
        QueryWrapper<Permission> query = new QueryWrapper<>();
        if (StringUtil.isNotEmpty(resource_name)) {
            query.like("resource_name", resource_name);
        }
        query.eq("belongs", belongs);
        query.eq("is_delete", "0");//是否删除
        query.orderByAsc("sort");//排序
        List<Permission> list = this.list(query); //查询所有
        list.forEach(it -> {
            if (StringUtil.isNotEmpty(it.getBackground_image()))
                it.setBg_image(fileReadPath + it.getBackground_image());
        });
        List<Permission> permissions = new ArrayList<>();
        //如果不传，默认为父级
        if (!StringUtil.isNotEmpty(pid)) {
            pid = "0";
        }
        for (Permission p : list) {
            if (pid.equals(p.getParent_id())) {
                //判断是否有子级
                boolean boo = false;
                for (Permission p1 : list) {
                    if (p.getId().equals(p1.getParent_id())) {
                        boo = true;
                        break;//跳出里面的for循环
                    }
                }
                p.setHas_children(boo);
                permissions.add(p);
            }
        }
        return permissions;
    }

    @Override
    public List<String> findButtonByUserId(String user_id) {
        List<String> buttons = permissionMapper.findButtonByUserId(user_id);
        return buttons;
    }

    @Override
    public boolean savePermission(Permission permission) {
        // 链接类型：：0：菜单，1：按钮，2：外部链接
        if ("1".equals(permission.getLink_type())) {// 按钮必须设置权限标识
            if (!StringUtil.isNotEmpty(permission.getButton_mark())) {
                throw new BusinessRuntimeException("按钮权限标识不能为空");
            }
            QueryWrapper<Permission> queryWrapper = new QueryWrapper();
            queryWrapper.eq("is_delete", "0");
            queryWrapper.eq("button_mark", permission.getButton_mark());
            List<Permission> list = this.list(queryWrapper);
            if (list.size() > 0) {
                throw new BusinessRuntimeException("权限标识不能重复");
            }
        }
        boolean boo = this.save(permission);
        //清除redis中的权限资源
        redisTemplate.delete(SysConstant.REDIS_ALL_PERMISSION);
        return boo;
    }

    @Override
    public boolean updatePermission(Permission permission) {
        // 链接类型：0：菜单，1：按钮，2：外部链接
        if ("1".equals(permission.getLink_type())) {// 按钮必须设置权限标识
            if (!StringUtil.isNotEmpty(permission.getButton_mark())) {
                throw new BusinessRuntimeException("按钮权限标识不能为空");
            }
            QueryWrapper<Permission> queryWrapper = new QueryWrapper();
            queryWrapper.eq("is_delete", "0");
            queryWrapper.eq("button_mark", permission.getButton_mark());
            queryWrapper.ne("id", permission.getId());
            List<Permission> list = this.list(queryWrapper);
            if (list.size() > 0) {
                throw new BusinessRuntimeException("权限标识不能重复");
            }
        }
        List<Permission> list = this.list();
        String ids = "";
        //自己的父id不能与自己相同
        if (permission.getId().equals(permission.getParent_id())) {
            throw new BusinessRuntimeException("上级菜单不能选择自己");
        }
        //所有子级父ID
        String allChildrenIds = allChildren(list, ids, permission.getId());
        String[] arr = allChildrenIds.split(",");
        //自己不能添加到自己的子级
        if (Arrays.asList(arr).contains(permission.getParent_id())) {
            throw new BusinessRuntimeException("上级菜单不能选择自己的子级菜单");
        }
        boolean boo = this.updateById(permission);
        //清除redis中的权限资源
        redisTemplate.delete(SysConstant.REDIS_ALL_PERMISSION);
        return boo;
    }

    //查询所有子级的父ID
    public String allChildren(List<Permission> list, String ids, String id) {
        if (isNotChildren(list, id)) {
            for (Permission permission : list) {
                if (id.equals(permission.getParent_id())) {
                    ids = allChildren(list, ids, permission.getId());
                    ids += permission.getId() + ",";
                }
            }
        }
        return ids;
    }

    //判断是否还有子级
    public boolean isNotChildren(List<Permission> list, String id) {
        boolean boo = false;
        for (Permission permission : list) {
            if (id.equals(permission.getParent_id())) {
                boo = true;
                break;
            }
        }
        return boo;
    }

    /**
     * 多级菜单查询方法
     *
     * @param pid 父类id
     * @return
     */
    public List<Permission> iterateMenus(List<Permission> permissionList, String pid, String resourceName) {
        List<Permission> parents = permissionList.stream().filter(it -> pid.equals(it.getParent_id())).collect(Collectors.toList());
        Iterator<Permission> iterator = parents.iterator();
        while (iterator.hasNext()) {
            Permission permission = iterator.next();
            if (StringUtil.isNotEmpty(resourceName) && !isSelfAndChildrenByName(permissionList, permission, resourceName)) {
                iterator.remove();//移除
            }
            //获取菜单的id
            String permissionId = permission.getId();
            if (isHasChildren(permissionList, permissionId)) {
                List<Permission> childrens = iterateMenus(permissionList, permissionId, resourceName);
                permission.setChildren(childrens);
            }
        }
        return parents;
    }

    // 判断是否还有子级
    public boolean isHasChildren(List<Permission> permissionList, String id) {
        return permissionList.stream().filter(it -> id.equals(it.getParent_id())).findFirst().isPresent();
    }

    // 判断自己和子级中是否包含这个部门名称（模糊查询）
    public boolean isSelfAndChildrenByName(List<Permission> permissionList, Permission parent, String resourceName) {
        boolean isContain = parent.getResource_name().contains(resourceName);
        isContain = isChildrenContain(permissionList, parent.getId(), resourceName, isContain);
        return isContain;
    }

    public boolean isChildrenContain(List<Permission> permissionList, String pId, String resourceName, boolean isContain) {
        if (!isContain) {//自己不包含，继续查
            List<Permission> childrens = permissionList.stream().filter(it -> it.getParent_id().equals(pId)).collect(Collectors.toList());//子级
            for (Permission children : childrens) {
                isContain = children.getResource_name().contains(resourceName);
                if (isContain) {
                    break;
                }
            }
            if (!isContain) {//子级均不包含,继续
                for (Permission children : childrens) {
                    isContain = isChildrenContain(permissionList, children.getId(), resourceName, isContain);
                    if (isContain) {
                        break;
                    }
                }
            }
        }
        return isContain;
    }

    @Override
    public List<Map<String, Object>> findResourceDetails(String id) {
        List<Map<String, Object>> list = permissionMapper.findResourceDetails(id);
        list.forEach(it -> {
            String role_depart = String.valueOf(it.get("role_depart"));
            if (StringUtil.isNotEmpty(role_depart)) {
                List<String> ids = Arrays.asList(role_depart.split(","));
                QueryWrapper<Depart> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("is_delete", "0");
                queryWrapper.in("id", ids);
                List<Depart> depts = departService.list(queryWrapper);
                List<String> collect = depts.stream().map(d -> d.getName()).collect(Collectors.toList());
                it.put("depart_name", Joiner.on(",").join(collect));
            }
        });
        return list;
    }
}
